local function makeattackspeed(inst, sg)
    --client
    inst:DoTaskInTime(0,function()
        --combat_replica
        local c_r = inst.replica.combat 
        c_r.attackspeedmult = net_float(inst.GUID, "attackspeedmult","onatkspeeddirty")
        c_r.attackspeedmult:set(1)
    end)

    if not TheWorld.ismastersim then return end 
    --server

    --combat
    local cb = inst.components.combat 
    cb.attackspeedmodifiers = SourceModifierList(inst, SourceModifierList.additive)
    cb.ori_min_attack_period = cb.min_attack_period
    local p = rawget(cb, "_")["min_attack_period"]
    local old_on_map = p[2]
    p[2] = function(self, map)
        old_on_map(self, map)
        self.inst.replica.combat.attackspeedmult:set(self.attackspeedmodifiers:Get())
    end

    function cb:SetAttackPeriod(val)
        self.ori_min_attack_period = val 
        self.min_attack_period = self.ori_min_attack_period / self.attackspeedmodifiers:Get()
    end

    function cb:SetAttackSpeedModifier(source, mult, key)
        self.attackspeedmodifiers:SetModifier(source, mult, key)
        self.min_attack_period = self.ori_min_attack_period / self.attackspeedmodifiers:Get()
    end

    function cb:RemoveAttackSpeedModifier(source, mult, key)
        self.attackspeedmodifiers:RemoveModifier(source, key)
        self.min_attack_period = self.ori_min_attack_period / self.attackspeedmodifiers:Get()
    end

    --sgspider
    if inst.sg.sg.name == (sg or "spider") then
        local sgw = inst.sg.sg
        local old_onenter = sgw.states["attack"].onenter
        sgw.states["attack"].onenter = function (inst,...)
            local res = old_onenter ~= nil and {old_onenter(inst,...)} or {}
            local combat = inst.components.combat
            local timeout = (math.floor(25/(combat.attackspeedmodifiers:Get())))*FRAMES
            inst.sg:SetTimeout(timeout)
            inst.AnimState:SetDeltaTimeMultiplier(combat.attackspeedmodifiers:Get())
            return unpack(res)
        end

        local old_ontimeout = sgw.states["attack"].ontimeout
        sgw.states["attack"].ontimeout = function (inst,...)
            inst:PerformBufferedAction()
            inst.sg:RemoveStateTag('abouttoattack')
            return old_ontimeout(inst,...)
        end

        local old_onexit = sgw.states["attack"].onexit
        sgw.states["attack"].onexit = function (inst,...)
            inst.AnimState:SetDeltaTimeMultiplier(1)
            return old_onexit(inst,...)
        end
    end
end

local function levelupfn(inst, data, source)
    local cmp = inst.components 
    --hp
    if data.iv.hp then
        cmp.health.maxhealth = cmp.health.maxhealth + data.iv.hp.grow 
    end
    --dmg
    if data.iv.dmg then
        cmp.combat.defaultdamage = cmp.combat.defaultdamage + data.iv.dmg.grow 
    end
    --wound
    if data.pr.wound then 
        local wound = data.pr.wound
        cmp.combat.externaldamagetakenmultipliers:SetModifier(inst, wound.val ^ wound.lv, 2)
    end
    --period
    if data.pr.period then 
        local period = data.pr.period 
        cmp.combat:SetAttackSpeedModifier(inst, period.val * math.log(1 + period.lv), 2)
    end
    --speed
    if data.pr.speed then 
        local speed = data.pr.speed
        cmp.locomotor:SetExternalSpeedMultiplier(inst, tun.speed + period.val * period.lv)
    end

end

local MakeSpider(name, extra_data)
    local assets = {}
    local prefabs = {name}

    local function updatedfn(name)
        return function()
            local inst = Prefabs[name].fn()

            if not TheWorld.ismastersim then return inst end 

            inst:AddComponent("spider_updater")
            local tun = TUNING.MOD_WEDDER.IDENTITY[name]
            local data = {
                iv = {
                    hp = {
                        start = tun.hp_start,
                        grow = tun.hp_glow,
                    },
                    dmg = {
                        start = tun.dmg_start,
                        grow = tun.dmg_grow,
                    },
                },
                pr = {
                    wound = {
                        pr = tun.wound_grow_chance,
                        val = tun.wound_per,
                    },
                    period = {
                        pr = tun.period_grow_chance,
                        val = tun.period_grow_factor,
                    },
                    speed = {
                        pr = tun.speed_grow_chance,
                        val = tun.speed_per,
                    },
                },
            }
            local iv = inst.components.spider_updater:Init(data)
            --hp init
            inst.components.health:SetMaxHealth(iv.health.start * inst.components.health.maxhealth)
            --dmg init
            inst.components.combat:SetDefaultDamage(iv.dmg.start)
            --wound init
            inst.components.combat.externaldamagetakenmultipliers:SetModifier(inst, tun.wound, 1)
            --period init
            makeattackspeed(inst, extra_data and extra.sg or nil)
            inst:DoTaskInTime(0, function()
                inst.components.combat:SetAttackSpeedModifier(inst, tun.period, 1)
            end)
            --speed init
            inst.components.locomotor:SetExternalSpeedMultiplier(inst, tun.speed)


            inst.components.spider_updater:SetLevelUpFn(levelupfn)

            return inst 
        end
    end

    return Prefab(name.."_updated", updatedfn, assets, prefabs)
end

local spiders = {
    "spider" = {},
    "spider_warrior" = {},
    "spider_healer" = {},
    "spider_hider" = {},
    "spider_spitter" = {},
    "spider_dropper" = {},
    "spider_water" = {sg = "spider_water"},
    "spider_moon" = {},
}

local spider_prefabs = {}
for spider, extra_data in pairs(spiders) do 
    table.insert(spider_prefabs, MakeSpider(spider, extra_data))
end

return unpack(spider_prefabs)